#define _GNU_SOURCE
#include "app_device.h"
#include "unistd.h"
#include "fcntl.h"
#include "stdlib.h"
#include "app_buffer.h"
#include "app_mqtt.h"
#include "app_pool.h"
#include "log/log.h"
#include "app_message.h"
#include "app_common.h"

#define DEVICE_BUFFER_SIZE 1024
#define DEVICE_THREAD_NUM 5
#define WRITE_INTERVAL_MS 200

static Device_t *device = NULL; // 单例模式

static int mqtt_send_task(void *arg)
{
    // 从缓冲区读取消息
    char data_buf[128];
    int read_len = app_buffer_read(device->up_buffer, data_buf, sizeof(data_buf));
    // 将字符数组消息转为json格式的字符数组
    char *json = app_message_CharsToJson(data_buf, read_len);
    // 发送消息到远程
    int ret = app_mqtt_publish(json);
    if (ret != 0)
    {
        log_error("发送消息失败");
        return -1;
    }
    else
    {
        log_debug("发送消息成功:%s", json);
        return 0;
    }
}

// 读线程函数
static void *app_device_read_thread(void *arg)
{
    // 不断的从串口文件中读取数据
    while (device->is_running)
    {
        char read_buf[128];
        int read_len = read(device->fd, read_buf, sizeof(read_buf));
        if (read_len > 0)
        {
            // 将读到的数据转化为字符数组
            if (device->read_post_fun)
            {
                read_len = device->read_post_fun(read_buf, read_len);
                log_debug("read_len:%d",read_len);
                if (read_len > 0)
                {
                    // 将数据写入到缓冲区
                    app_buffer_write(device->up_buffer, read_buf, read_len);
                    // 然后不断的发送数据 ==> 线程池
                    app_pool_registerTask(mqtt_send_task, NULL);
                }
            }
        }
    }
}

// 写入任务
static int device_write_task(void *arg)
{
    char read_buf[128];
    // 从缓冲区读数据
    int read_len = app_buffer_read(device->down_buffer, read_buf, sizeof(read_buf));
    // 定义上一次的时间
    static long last_time = 0;
    // 将字符数组转换为设备数据格式
    if (read_len > 0 && device->write_pre_fun != NULL)
    {
        read_len = device->write_pre_fun(read_buf, read_len);
        if (read_len > 0)
        {
            long current_time = app_common_getCurrentTime();
            // 写之前，需要保证与上次写入的时间间隔不小于WRITE_INTERVAL_MS
            long interval = current_time - device->last_write_time;
            if (interval < WRITE_INTERVAL_MS)
            {
                // 为了防止等待的过程再来一个线程 需要及时更新last_time
                last_time = current_time + (WRITE_INTERVAL_MS - interval);
                usleep((WRITE_INTERVAL_MS - interval) * 1000);
            }
            else
            {
                last_time = current_time;
            }

            // 写入
            ssize_t write_len = write(device->fd, read_buf, read_len);
            if (write_len != read_len)
            {
                log_error("写入设备失败");
                return -1;
            }
            // 保存写入的时间
            device->last_write_time = app_common_getCurrentTime();
            log_debug("写入设备成功,长度:%d", write_len);
            return 0;
        }
    }
}

// 接收处理远程消息的回调
static int app_device_recv_callback(char *json_data)
{
    // 将json数据转换成字符数据
    char data_buf[128];
    int len = app_message_JsonToChars(json_data, data_buf, sizeof(data_buf));
    // 将数据写入到设备缓冲区
    app_buffer_write(device->down_buffer, data_buf, len);
    // 将消息数据写入到设备文件 ==> 交给线程池
    app_pool_registerTask(device_write_task, NULL);
}

Device_t *app_device_init(char *fileName)
{
    if (device)
    {
        return device;
    }
    device = (Device_t *)malloc(sizeof(Device_t));
    // 文件名
    device->fileName = fileName;
    device->fd = open(fileName, O_RDWR);
    device->up_buffer = app_buffer_init(DEVICE_BUFFER_SIZE);
    device->down_buffer = app_buffer_init(DEVICE_BUFFER_SIZE);
    device->is_running = 0;
    device->last_write_time = 0;
    device->read_post_fun = NULL;
    device->write_pre_fun = NULL;

    // 初始化相关模块
    app_mqtt_init();
    app_pool_init(DEVICE_THREAD_NUM);
    return device;
}

int app_device_start(void)
{
    // 启动相关模块
    if (device->is_running)
    {
        return 0;
    }
    device->is_running = 1;
    // 启动设备读线程
    pthread_create(&device->read_thread, NULL, app_device_read_thread, NULL);
    // 接收远程设备发来的消息
    app_mqtt_registerRecvCallback(app_device_recv_callback);
    return 0;
}

int app_device_stop(void)
{
    device->is_running = 0;
    pthread_cancel(device->read_thread);
    close(device->fd);
    app_buffer_free(device->down_buffer);
    app_buffer_free(device->up_buffer);
    device->read_post_fun = NULL;
    device->write_pre_fun = NULL;
    device->last_write_time = 0;
    app_mqtt_close();
    app_pool_destroy();
    return 0;
}
